package com.wm.practice;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: CompletableFutureApiDemo2
 * @Description: CompletableFuture的Api示例2
 * @Author: Deamer
 * @Date: 2022/9/3 16:42
 **/
public class CompletableFutureApiDemo2 {
    /**
     * @param args
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
    }

    /**
     * 线程结果和
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void thenCombineApi() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " \t " + "---come in ");
            // 暂停2秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " \t " + "---come in ");
            // 暂停1秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        });
        CompletableFuture<Integer> thenCombineResult = completableFuture1.thenCombine(completableFuture2, (x, y) -> {
            System.out.println(Thread.currentThread().getName() + " \t " + "---come in ");
            return x + y;
        });
        System.out.println(thenCombineResult.get());
    }

    /**
     * 线程比效率，谁快用谁
     *
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void applyToEitherApi() throws InterruptedException, ExecutionException {
        CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " \t " + "---come in ");
            // 暂停2秒钟线程
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 10;
        });
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " \t " + "---come in ");
            // 暂停1秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 20;
        });
        CompletableFuture<Integer> thenCombineResult = completableFuture1.applyToEither(completableFuture2, f -> {
            System.out.println(Thread.currentThread().getName() + " \t " + "---come in ");
            return f + 1;
        });
        System.out.println(Thread.currentThread().getName() + " \t " + thenCombineResult.get());
    }

    /**
     * 返回结果API
     */
    private static void resultApi() {
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {
        }).join());
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {
        }).join());
        System.out.println(CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB").join());
    }

    /**
     * 接收任务的处理结果，并消费处理，无返回结果，消费型函数式接口
     */
    private static void functionApi() {
        CompletableFuture.supplyAsync(() -> {
            return 1;
        }).thenApply(f -> {
            return f + 2;
        }).thenApply(f -> {
            return f + 3;
        }).thenApply(f -> {
            return f + 4;
        }).thenAccept(r -> {
            System.out.println(r);
        });
    }

    /**
     * ---主线程结束
     * 111
     * 333
     * 返回值v:null
     * 异常信息【可以看出多走了一个333】
     */
    private static void handleTest() {
        //当一个线程依赖另一个线程时用 thenApply 方法来把这两个线程串行化
        CompletableFuture.supplyAsync(() -> {
            // 暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1024;
        }).handle((f, e) -> {
            // 异常语句
            int age = 10 / 0;
            System.out.println("222");
            return f + 1;
        }).handle((f, e) -> {
            System.out.println("333");
            return f + 1;
        }).whenCompleteAsync((v, e) -> {
            System.out.println("返回值v:" + v);
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });
        System.out.println("---主线程结束");
        // 主线程不要立刻结束，否则CompletableFuture默认使用的线程池会立刻关闭:
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (
                InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 正常情况结果：
     * ---主线程结束
     * 111
     * 222
     * 333
     * 返回值v:1026
     * <p>
     * 错误情况结果：
     * ---主线程结束
     * 111
     * 返回值v:null
     * 异常信息...
     */
    private static void thenApplyTest() {
        //当一个线程依赖另一个线程时用 thenApply 方法来把这两个线程串行化
        CompletableFuture.supplyAsync(() -> {
            // 暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("111");
            return 1024;
        }).thenApply(f -> {
            // 异常情况：哪步出错就停在哪步。
            //  int age = 10 / 0;
            System.out.println("222");
            return f + 1;
        }).thenApply(f -> {
            System.out.println("333");
            return f + 1;
        }).whenCompleteAsync((v, e) -> {
            System.out.println("返回值v:" + v);
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });
        System.out.println("---主线程结束");
        // 主线程不要立刻结束，否则CompletableFuture默认使用的线程池会立刻关闭:
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (
                InterruptedException e) {
            e.printStackTrace();
        }
    }
}
